// filter by key, it will display only keys with format `VALUE_<string>`
// usage: FilterCodeKeys<myKeyObject>
type FilterCodeKeys<T extends object> = {
  [K in keyof T]: K extends `VALUE_${string}` ? K : never;
}[keyof T];





type PathImpl<T, K extends keyof T, S extends PathSep> = K extends string
  ? T[K] extends Record<string, any>
    ? T[K] extends ArrayLike<any>
      ? K | `${K}${S}${PathImpl<T[K], Exclude<keyof T[K], keyof any[]>, S>}`
      : K | `${K}${S}${PathImpl<T[K], keyof T[K], S>}`
    : K
  : never;

type PathSep = '.' | ':';

/**
 * Lists the valid paths for a given type
 *
 * @example
 *   interface Store {
 *      key: { value: number; };
 *      discriminant: string;
 *   }
 *   type StorePath = Path<Store>; // 'key.value' | 'discriminant'
 */
export type Path<T, S extends PathSep = '.'> = PathImpl<T, keyof T, S> | keyof T;

export type PathValue<
  T,
  P extends Path<T>,
  S extends PathSep = '.'
> = P extends `${infer K}${S}${infer Rest}`
  ? K extends keyof T
    ? Rest extends Path<T[K]>
      ? PathValue<T[K], Rest>
      : never
    : never
  : P extends keyof T
  ? T[P]
  : never;

/**
 * Extends the `Pick` utility type
 *
 * @example
 *
 *   interface Foo {
 *     a: number;
 *     b: number;
 *     c: string;
 *   }
 *   type OnlyNumbersOfFoo = PickWhere<Foo, number>;
 *   // equivalent to
 *   interface OnlyNumbersOfFoo {
 *     a: number;
 *     b: number;
 *   }
 */
export type PickWhere<T, Condition> = Pick<
  T,
  {
    [K in keyof T]: T[K] extends Condition ? K : never;
  }[keyof T]
>;

export type ComparablePath<T> = {
  [P in Path<T>]: PathValue<T, P> extends string | number ? P : never;
}[Path<T>];

/**
 * Extracts the values of a const object/tuple as types
 *
 * @example
 *   const NAMED_ENUM = { foo: 'foo', bar: 'bar' } as const;
 *   type Enum = ValuesOf<typeof NAMED_ENUM>; // 'foo' | 'bar'
 *
 *   const TUPLE = ['a', 'b', 'c'] as const;
 *   type Tuple = ValuesOf<typeof Tuple>; // 'a' | 'b' | 'c'
 */
export type ValuesOf<T extends Record<string, unknown> | readonly [...unknown[]]> =
  T extends Record<string, unknown>
    ? T[keyof T]
    : T extends readonly [...unknown[]]
    ? T[number]
    : never;

